<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="./vue.js"></script>
    <script src="./factory.js"></script>
    <link rel="stylesheet" href="./dist/output.css" />
  </head>
  <body class="felx items-center justify-center">
    <div id="app"></div>
    <script type="text/x-template" id="App">
      <div id="app">
         <!-- <template v-for="item in schema">
             <component :key="item.fieldId"  v-bind="getProps(item)" :is="getComponent(item)" ></component>
         </template>  -->
         <FormRender v-if="isRender" :schema="schema" :formData="formData"></FormRender>
         <button type="button" @click="destroy" class="border button" style="cursor: pointer;">卸载和渲染组件</button>
         <button type="button" @click="resetForm" class="border button" style="cursor: pointer;">重置表单</button>
      </div>
    </script>
    <script type="text/x-template" id="Select">
      <div>
          <label class="inline-flex">
              <div v-if="schemaJson.showLabel !== false" class="w-[120px] text-right text-gray-600">{{schemaJson.label}}：</div>
              <select  v-model="bind.model[bind.key]" class="text-[#2b2b2b] rounded-[2px] w-[240px] border border-[#a7a7a7] px-[10px] py-[2px] h-[32px] text-ellipsis overflow-hidden whitespace-nowrap box-border outline-none hover:border-amber-500 focus:border-amber-500 focus:shadow-[0px_0px_0px_2px_#f9d0ad]">
                <option v-for="item in list" :value="item">{{item}}</option>
              </select>
           </label>
      </div>
    </script>
    <script type="text/x-template" id="InputText">
      <label class="inline-flex">
          <div v-if="schemaJson.showLabel !== false" class="w-[120px] text-right text-gray-600">{{schemaJson.label}}：</div>
          <input  type="text" class="text-[#2b2b2b] rounded-[2px] w-[240px] border border-[#a7a7a7] px-[10px] py-[2px] h-[32px] text-ellipsis overflow-hidden whitespace-nowrap box-border outline-none hover:border-amber-500 focus:border-amber-500 focus:shadow-[0px_0px_0px_2px_#f9d0ad]" v-model="bind.model[bind.key]">
      </label>
    </script>
    <script type="text/x-template" id="Group">
      <div class="group">
         <div class="flex">
          <div v-if="schemaJson.showLabel !== false" class="w-[120px] text-right text-gray-600 shrink-0">{{schemaJson.label}}：</div>
          <!-- <div class="border p-[20px] mr-[20px]"><slot></slot></div> -->
          <div>
            <table>
                <thead>
                    <tr>
                        <th class="!text-center">序号</th>
                        <th v-for="item in schemaJson.children">{{item.label}}</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="(row,rowIndex) in renderSchema">
                        <td class="max-w-[30px] text-center">{{rowIndex+1}}</td>
                        <td v-for="col in row"> <component v-bind="getProps(col.componentOptions.propsData)" :showLabel="false" :is="col.componentOptions.Ctor" ></component></td>
                        <td><button v-if="bind.model[bind.key].length>1" type="button" class="button"  @click="deleteRow(rowIndex)" >删除数据</button></td>
                    </tr>
                    <tr>
                       <td :colspan="schemaJson.children.length+2" class="bg-gray-100"><button type="button" @click="addRow" class="border-amber-600 border bg-amber-600 text-white text-[12px] hover:bg-amber-500 hover:border-amber-500 px-[10px] py-[4px] rounded-[2px] cursor-pointer" >添加数据</button></td>
                    </tr>
                </tbody>
            </table>
        </div>
         </div>
      </div>
    </script>
    <script type="text/x-template" id="Form">
      <div class="mt-[50px]">
         <slot></slot>
      </div>
    </script>
    <script>
      const Form = Vue.component("Form", {
        template: "#Form",
      });
      const Group = Vue.component("Group", {
        template: "#Group",
        props: ["bind", "schemaJson"],
        templateData: "",
        data() {
          return {
            renderSchema: [],
          };
        },
        methods: {
          getProps(propsData){
            Object.assign(propsData.schemaJson, {
              showLabel:false
            });
            console.log(propsData,"propsData")
            return propsData;
          },
          addRow() {
          
            this.bind.model[this.bind.key].push(
              JSON.parse(this.$options.templateData)
            );
            console.log(this.bind.model[this.bind.key], "this.bind.model");
          },
          deleteRow(rowInddex) {
            this.bind.model[this.bind.key].splice(rowInddex, 1);
          },
        },
        mounted() {
          this.$options.templateData = JSON.stringify(
            this.bind.model[this.bind.key][0]
          );

          function splitArrayIntoGroupsOfThree(arr,len) {
            let result = [];
            for (let i = 0; i < arr.length; i += len) {
              result.push(arr.slice(i, i + len));
            }
            return result;
          }

          
          this.$watch(
            () => this.bind.model[this.bind.key],
            (v, old) => {
              const spLen = this.schemaJson.children.length;
              this.renderSchema = splitArrayIntoGroupsOfThree(this.$slots.default,spLen);
            },
            {
              immediate: true,
            }
          );
        },
      });
      const Select = Vue.component("Select", {
        template: "#Select",
        props: ["bind", "schemaJson", "showLabel"],
        data() {
          return {
            list: ["1", "2", "3", "4", "5"],
          };
        },
        methods: {
          change(e) {
            console.log(e.target.value);
          },
        },
        mounted() {
          console.log(this.schemaJson, "this.schemaJson");
        },
      });
      const InputText = Vue.component("InputText", {
        template: "#InputText",
        props: ["bind", "schemaJson", "showLabel"],
        data() {
          return {
            value: "",
          };
        },
        methods: {
          change(e) {
            console.log(e.target.value);
          },
        },
        beforeDestroy() {
          //  console.log("组件卸载");
        },
        mounted() {
          console.log(this.schemaJson, "this.props");
        },
      });

      const components = {
        Select,
        InputText,
        Form,
        Group,
      };

      function setupObserver(vm) {
        const {
          bind: { model, key, path },
          schemaJson,
          schemaItem,
        } = vm;
        // console.log("created-FormItem",schemaJson);
        console.log(path,"path---------")
        if (!schemaItem) {
          // console.log("创建schemaItem", parent, schemaJson);
          const schemaItem = new Factory(schemaJson, vm.model, path);
          vm.schemaItem = schemaItem;
        }

        vm._shouldUnsubscribe && vm._shouldUnsubscribe();
        vm._shouldUnsubscribe = vm.$watch(
            "model"+"."+path,
            (v, old) => {
              console.log(vm.bind, "数据变化");
              vm.schemaItem.change.call(vm.schemaItem, v, old);
            },
            {
              immediate: false,
            }
          );

        // if (!vm._shouldUnsubscribe) {
        //   // console.log("重新订阅")
        //   vm._shouldUnsubscribe = vm.$watch(
        //     () => model[key],
        //     (v, old) => {
        //       console.log("数据变化")
        //       vm.schemaItem.cahnge(v, old);
        //     },
        //     {
        //       immediate: true
        //     }
        //   );
        // }
      }

      const FormItem = {
        props: ["schemaJson", "bind", "C", "model"],
        name: "FormItem",
        destroyed() {
          // console.log("卸载-FormItem",this._shouldUnsubscribe,this.schemaItem.fieldId);
          this._shouldUnsubscribe && this._shouldUnsubscribe();
          this.schemaItem && this.schemaItem.destroy();
          this._shouldUnsubscribe = null;
          this.schemaItem = null;
        },
        data() {
          return {
            schemaItem: null,
          };
        },
        beforeMount() {
          if (this.bind) {
            setupObserver(this);
          }
        },
        render(h) {
          console.log("this.schemaItem-render",this.schemaItem);
         
          if (this.schemaItem && this.schemaItem.display === "none") {
            return null;
          }
          if (Array.isArray(this.schemaJson)) {
            const childrens = this.schemaJson.map((item) => {
              const bind = {
                model: this.model,
                key: item.fieldId,
                path: item.fieldId,
              };
             
              return h(FormItem, {
                props: {
                  schemaJson: item,
                  bind: bind,
                  C: item.component,
                  model: this.model,
                },
              });
            });
            const Com = components[this.C];

            const renderComponent = h(
              Com,
              {
                props: {
                  bind: this.bind,
                  schemaJson: this.schemaItem,
                  showLabel: true,
                },
              },
              childrens
            );
            console.log("渲染表单", this.C);
            return h("div", { class: "mb-[10px]" }, [renderComponent]);
          } else {
            console.log("渲染单个组件", this.C, this.bind);
            const parentPath = this.bind.path
            // const parentModel = this.bind.model[this.bind.key]
            const getChildrens = (schemaJson, model) => {
              const childrens = model.map((item, index) => {
                const scopeModel = item;
                return schemaJson.map((itemSchema) => {
                  const bind = {
                    model: scopeModel,
                    key: itemSchema.fieldId,
                    path: parentPath + "." + index+ '.' + itemSchema.fieldId,
                  };
                  return h(FormItem, {
                    props: {
                      schemaJson: itemSchema,
                      bind,
                      C: itemSchema.component,
                      model: this.model,
                      parent: this.schemaItem,
                    },
                  });
                });
              });
              return childrens;
            };

            const childrens = this.schemaItem.children
              ? getChildrens(
                  this.schemaItem.children,
                  this.bind.model[this.bind.key]
                )
              : [];
            const Com = components[this.C];
            const renderComponent = h(
              Com,
              {
                props: {
                  bind: this.bind,
                  schemaJson: this.schemaItem,
                },
              },
              childrens
            );
            return h("div", { class: "form-item mb-[10px]" }, [renderComponent]);
          }
        },
      };

      const FormRender = {
        props: ["schema", "formData"],
        data() {
          return {
            key: 0,
          };
        },
        watch: {
          formData() {
            this.key = this.key + 1;
          },
        },
        created() {
          console.log("重新执行-FormRender");
        },
        render(h) {
          return h(FormItem, {
            key: this.key,
            props: {
              schemaJson: this.schema,
              bind: null,
              model: this.formData,
              C: "Form",
            },
          });
        },
      };

      const App = Vue.component("App", {
        template: "#App",
        components: {
          FormRender,
        },
        data() {
          return {
            isRender: true,
            formData: {
              select_001: "1",
              input_001: "input_001",
              input_002: "input_002",
              input_003: [
                {
                  input_004: "input_004",
                  input_005: "2",
                  input_009: "3",
                  input_006: [
                    {
                      input_007: "input_007",
                      input_008: "input_008",
                    },
                  ],
                },
              ],
            },
            schema: [
              {
                fieldId: "select_001",
                component: "Select",
                label: "选择框",
                required: true,
                display: "visible",
                triggers: {
                  "x-display": [
                    {
                      fieldId: "input_001",
                      value: ["2"],
                    },
                    {
                      fieldId: "input_002",
                      value: ["3"],
                    },
                  ],
                },
              },
              {
                fieldId: "input_001",
                component: "InputText",
                label: "输入框",
                triggers: {
                  "x-display": [],
                },
                required: true,
                display: "visible",
              },
              {
                fieldId: "input_002",
                component: "InputText",
                label: "输入框12",
                triggers: {
                  "x-display": [],
                },
                required: true,
                display: "visible",
              },
              {
                fieldId: "input_003",
                component: "Group",
                label: "表单组",
                triggers: {
                  "x-display": [],
                },
                required: true,
                display: "visible",
                children: [
                  {
                    fieldId: "input_004",
                    component: "InputText",
                    label: "输入框13",
                    triggers: {
                      "x-display": [],
                    },
                    required: true,
                    display: "visible",
                  },
                  {
                    fieldId: "input_005",
                    component: "Select",
                    label: "选择框",
                    triggers: {
                      "x-display": [
                        {
                          fieldId: "input_006",
                          value: ["1"],
                        },
                      ],
                    },
                    required: true,
                    display: "visible",
                  },
                  {
                    fieldId: "input_006",
                    component: "Group",
                    label: "表单组",
                    triggers: {
                      "x-display": [],
                    },
                    required: true,
                    display: "visible",
                    children: [
                      {
                        fieldId: "input_007",
                        component: "InputText",
                        label: "输入框13",
                        triggers: {
                          "x-display": [],
                        },
                        required: true,
                        display: "visible",
                      },
                      {
                        fieldId: "input_008",
                        component: "InputText",
                        label: "输入框14",
                        triggers: {
                          "x-display": [],
                        },
                        required: true,
                        display: "visible",
                      },
                    ],
                  },
                  {
                    fieldId: "input_009",
                    component: "Select",
                    label: "选择框",
                    triggers: {
                      "x-display": [
                        {
                          fieldId: "input_006",
                          value: ["1"],
                        },
                      ],
                    },
                    required: true,
                    display: "visible",
                  },
                  {
                    fieldId: "input_0010",
                    component: "InputText",
                    label: "文本input_0010",
                    triggers: {
                      "x-display": [],
                    },
                    required: true,
                    display: "visible",
                  },
                ],
              },
            ],
          };
        },
        methods: {
          destroy() {
            // alert("卸载和渲染组件");
            // 卸载和渲染组件
            // this.$destroy();
            this.isRender = !this.isRender;
          },
          resetForm() {
            //  this.formData = this.$options.data().formData;
            this.$set(this, "formData", this.$options.data().formData);
          },
        },
        mounted() {
          window.getJson = () => {
            return this.schema;
          };
          window.getFormData = () => {
            return this.formData;
          };
        },
      });

      const rootVm = new Vue({
        render(h) {
          return h(App);
        },
      }).$mount("#app");
    </script>
  </body>
</html>
